{"cells":[{"cell_type":"markdown","metadata":{"cell_id":"989ef86ee7614e199ae7c5486aa5ec62","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-h1","formattedRanges":[]},"source":["# Mahilo As Your Agent Control Plane"]},{"cell_type":"markdown","metadata":{"cell_id":"362043ff1e3a4b92828cb1d52f9fc7e5","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[]},"source":["With the advent of increasingly powerful models, the use of specialized agents would grow considerably. We already have powerful agents that you can hire for your organization, performing tasks like marketing, sales or product management. In a world where these agents are expected to work together, it becomes important that they are aware of each other and can share information as needed to get better at their jobs, instead of working in silos."]},{"cell_type":"markdown","metadata":{"cell_id":"ba008616da64480f8650c21703031b2d","deepnote_app_block_visible":true,"deepnote_cell_type":"image","deepnote_img_src":"image-20241226-154404.png"},"source":["![Mahilo Agents](./mahilo_integrations1.png)"]},{"cell_type":"markdown","metadata":{"cell_id":"cc3d81f1b2f84473b90dcc307094e8bf","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[{"fromCodePoint":0,"ranges":[{"fromCodePoint":0,"marks":{"bold":true},"toCodePoint":6,"type":"marks"}],"toCodePoint":6,"type":"link","url":"https://github.com/wjayesh/mahilo"},{"fromCodePoint":6,"marks":{"bold":true},"toCodePoint":7,"type":"marks"}]},"source":["mahilo is a multi-agent human-in-the-loop framework that ties agents together while allowing humans to supervise them in real-time. Bring any agent, irrespective of the framework it is written in (or from a proprietary service) and mahilo can enable you to connect it to your team of agents, allowing cross-communication and enforcement of common company policies."]},{"cell_type":"markdown","metadata":{"cell_id":"65e272ff103a414a8a7a41ea7eb65465","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[{"fromCodePoint":31,"ranges":[],"toCodePoint":40,"type":"link","url":"https://langchain-ai.github.io/langgraph/"},{"fromCodePoint":45,"ranges":[],"toCodePoint":55,"type":"link","url":"https://ai.pydantic.dev/"}]},"source":["Let's look at an example using LangGraph and PydanticAI agents (the two frameworks supported at the moment)."]},{"cell_type":"markdown","metadata":{"cell_id":"7e3fc560f7a8406f84246bb74f6e3eef","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-h1","formattedRanges":[]},"source":["# Use Case: Sales, Marketing, and Product Teams in a Company"]},{"cell_type":"markdown","metadata":{"cell_id":"7034232e304040ed9290e08bf48ad5f5","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[{"fromCodePoint":156,"marks":{"bold":true},"toCodePoint":184,"type":"marks"}]},"source":["Let's take the use case of a company with three teams that need to coordinate with each other across multiple tasks. The scenario we will focus on is this: Feature Launch Coordination."]},{"cell_type":"markdown","metadata":{"cell_id":"9ebfcdb2ce414a9590d01474c70f9a62","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[]},"source":["The setup is such that each team gets an agent that is supervised by a human supervisor. We will start our discourse with the sales agent about a potential new feature, which will then use its capabilities to decide what course of action to take, eventually discussing the idea and its roadmap with the product agent, which in turn gets the marketing agent in the loop for preparing promotion material. All of this, while their human supervisors have direct knowledge of what's going on and can guide and approve the agents' actions."]},{"cell_type":"markdown","metadata":{"cell_id":"ecf79a135e084f5cb160b023cd13cf2b","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-h1","formattedRanges":[]},"source":["# Building the Agents"]},{"cell_type":"markdown","metadata":{"cell_id":"d163f9ea377f4c30845176d447f5764e","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-h2","formattedRanges":[]},"source":["## Setup"]},{"cell_type":"markdown","metadata":{"cell_id":"935c4b5bd7ad4630b138860795c1a9f4","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[]},"source":["Let's first install some libraries and set our OpenAI API key, which is the provider we will use for the demo."]},{"cell_type":"code","execution_count":1,"metadata":{"cell_id":"1e18cfd4a14245779becb60229320302","deepnote_app_block_visible":true,"deepnote_app_is_code_hidden":false,"deepnote_app_is_output_hidden":false,"deepnote_cell_type":"code","execution_context_id":"e9747ad3-6909-4e81-a10a-fa1694eb9151","execution_millis":8644,"execution_start":1735200050827,"source_hash":"5e73bd8f"},"outputs":[],"source":["import getpass\n","import os\n","\n","os.environ[\"OPENAI_API_KEY\"] = getpass.getpass(\"Enter your OpenAI API key: \")"]},{"cell_type":"code","execution_count":null,"metadata":{"cell_id":"b2a649509b6f45889f23bd3cb0104cb0","deepnote_app_block_visible":true,"deepnote_app_is_code_hidden":false,"deepnote_app_is_output_hidden":false,"deepnote_cell_type":"code","execution_context_id":"e9747ad3-6909-4e81-a10a-fa1694eb9151","execution_millis":11981,"execution_start":1735200062294,"is_output_hidden":true,"source_hash":"7958d4a9"},"outputs":[],"source":["!pip install -r requirements.txt"]},{"cell_type":"markdown","metadata":{"cell_id":"8dc2aa03d24e4129ba174e9c5b54c543","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-h2","formattedRanges":[]},"source":["## Marketing Agent (LangGraph)"]},{"cell_type":"markdown","metadata":{"cell_id":"362bd277759e4e889a76d24281ee9e8d","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[{"fromCodePoint":200,"marks":{"code":true},"toCodePoint":208,"type":"marks"}]},"source":["We'll start with the marketing agent and will utilize LangGraph to build it. To build an agent that can be registered with mahilo later, all you need to do is add a tool that mahilo provides, to your ToolNode when defining your graph. "]},{"cell_type":"markdown","metadata":{"cell_id":"49de394c6ac446e38cefe32e70cc8a7c","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[]},"source":["You can then go about building the agent without worrying about any additional syntax and choose whatever tools suit your needs. In the example below, we have chosen three tools for the marketing agent:"]},{"cell_type":"markdown","metadata":{"cell_id":"1f0a05d82c63449b97dbe785ab363799","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-bullet","formattedRanges":[{"fromCodePoint":0,"marks":{"code":true},"toCodePoint":27,"type":"marks"}]},"source":["- analyze_content_performance: Analyze the performance of the content across social media platforms\n","- research_trending_topics: Research current trending topics in the industry\n","- generate_content_calendar: Create a content calendar based on trends and performance"]},{"cell_type":"markdown","metadata":{"cell_id":"2863109c31874908a6da3bf618cd9abc","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[]},"source":["We expect this agent to answer questions about what platforms have performed well, what is the current market sentiment around relevant topics and to generate content calendars based on all the information it gathers. You can imagine that this agent will benefit from knowing specific product details when choosing what to promote, from the product team and also where most sales leads are coming from, from the sales team."]},{"cell_type":"code","execution_count":4,"metadata":{"cell_id":"045745c7b1ed45089dea4ff6dd037428","deepnote_app_block_visible":true,"deepnote_app_is_code_hidden":false,"deepnote_app_is_output_hidden":false,"deepnote_cell_type":"code","execution_context_id":"e9747ad3-6909-4e81-a10a-fa1694eb9151","execution_millis":1211,"execution_start":1735200074334,"source_hash":"a5fb4471"},"outputs":[{"data":{"text/plain":["<langgraph.graph.state.StateGraph at 0x7fa429b12190>"]},"execution_count":4,"metadata":{},"output_type":"execute_result"}],"source":["from typing import Annotated, Dict, List\n","\n","from langchain_openai import ChatOpenAI\n","from typing_extensions import TypedDict\n","\n","from langgraph.checkpoint.memory import MemorySaver\n","from langgraph.graph import StateGraph\n","from langgraph.graph.message import add_messages\n","from langgraph.prebuilt import ToolNode, tools_condition\n","\n","# the tool that mahilo provides out-of-the-box\n","from mahilo.integrations.langgraph.tools import get_chat_with_agent_tool_langgraph\n","\n","memory = MemorySaver()\n","\n","class State(TypedDict):\n","    messages: Annotated[list, add_messages]\n","\n","graph_builder = StateGraph(State)\n","\n","from langchain_core.tools import tool\n","\n","@tool\n","def analyze_content_performance(content: str) -> str:\n","  \"\"\"Analyze the performance of the content across social media platforms\"\"\"\n","  return \"The content is performing well on LinkedIn.\"\n","\n","@tool\n","def research_trending_topics(industry: str) -> List[str]:\n","    \"\"\"Research current trending topics in the industry\"\"\"\n","    return [\"Lot of buzz around mahilo agents and its multi-agent capabilities\"]\n","\n","@tool\n","def generate_content_calendar(timeframe: str) -> Dict[str, str]:\n","    \"\"\"Create a content calendar based on trends and performance\"\"\"\n","    return {\n","        \"January\": \"Mahilo Agents: Multi-Agent Capabilities\",\n","        \"February\": \"Integrations with mahilo\",\n","    }\n","\n","chat_with_agent_tool = get_chat_with_agent_tool_langgraph()\n","tools = [analyze_content_performance, research_trending_topics, generate_content_calendar, chat_with_agent_tool]\n","llm = ChatOpenAI(model=\"gpt-4o-mini\")\n","llm_with_tools = llm.bind_tools(tools)\n","\n","def chatbot(state: State):\n","    return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n","\n","graph_builder.add_node(\"chatbot\", chatbot)\n","\n","tool_node = ToolNode(tools=tools)\n","graph_builder.add_node(\"tools\", tool_node)\n","\n","graph_builder.add_conditional_edges(\n","    \"chatbot\",\n","    tools_condition,\n",")\n","graph_builder.add_edge(\"tools\", \"chatbot\")\n","graph_builder.set_entry_point(\"chatbot\")"]},{"cell_type":"markdown","metadata":{"cell_id":"ae2604a68fc54bb5a9aeef7c6666c06a","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[]},"source":["The code above builds a simple graph that starts at the chatbot and has a tools node that is called conditionally if the response of the chatbot contains any tool calls. The functions have dummy logic but you can imagine that this agent in production could be a state-of-the-art, well-tested system that specializes in marketing."]},{"cell_type":"markdown","metadata":{"cell_id":"bffef25a2cb74bcaa9e71e2f04631945","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-callout","formattedRanges":[],"is_collapsed":false},"source":["> ℹ️ mahilo also supports setting thread ID when running the agent. We will see this in the control plane section below when we bring these agents together."]},{"cell_type":"code","execution_count":30,"metadata":{"cell_id":"6e46d25e502242b2b00a791eba81d1f4","deepnote_app_block_visible":true,"deepnote_app_is_code_hidden":false,"deepnote_app_is_output_hidden":false,"deepnote_cell_type":"code","execution_context_id":"e9747ad3-6909-4e81-a10a-fa1694eb9151","execution_millis":54,"execution_start":1735201772811,"source_hash":"88f60549"},"outputs":[{"data":{"image/png":"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","text/plain":["<IPython.core.display.Image object>"]},"metadata":{"image/png":{"height":249,"width":214}},"output_type":"display_data"}],"source":["from IPython.display import Image, display\n","\n","graph = graph_builder.compile()\n","\n","try:\n","    display(Image(graph.get_graph().draw_mermaid_png()))\n","except Exception:\n","    # This requires some extra dependencies and is optional\n","    pass"]},{"cell_type":"markdown","metadata":{"cell_id":"1622d16dd0f24c7083a60f08a8aae1f0","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-h2","formattedRanges":[]},"source":["## Product Agent (PydanticAI)"]},{"cell_type":"markdown","metadata":{"cell_id":"c8b8a924f7ce407d9c23f92af29cb699","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[{"fromCodePoint":167,"marks":{"bold":true},"toCodePoint":187,"type":"marks"}]},"source":["The next agent we will build is a product manager agent, built using PydanticAI. To build an agent that can later be integrated into mahilo, you don't have to perform any additional tasks! mahilo can take your PydanticAI agent as it is, and integrate it into its network of AI agents."]},{"cell_type":"markdown","metadata":{"cell_id":"6b495627468a48e38eaaa627c5a71cda","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[]},"source":["The product agent below has the following functions:"]},{"cell_type":"markdown","metadata":{"cell_id":"d0d9486a2c5449c7a320e87abcdf57b4","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-bullet","formattedRanges":[{"fromCodePoint":0,"marks":{"code":true},"toCodePoint":23,"type":"marks"}]},"source":["- analyze_feature_request: Analyze viability and impact of requested features\n","- get_product_roadmap: Get current product roadmap and timeline from the database connection\n","- analyze_usage_patterns: Analyze how customers are using specific features"]},{"cell_type":"markdown","metadata":{"cell_id":"5fa7faeffe5645a995f44bb7ed3e33fb","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[]},"source":["We expect this agent to be able to analyze a feature request, figure out when it is planned and then discuss with its human supervisor if it needs to be reprioritized. It can also analyze patterns and come up with features to build. You can imagine that this agent would be really helpful for the sales agent to get up-to-date information about the product and motivate priorities based on customer feedback. This agent also has to work closely with the marketing team to keep them in the loop for upcoming features."]},{"cell_type":"code","execution_count":16,"metadata":{"cell_id":"b59caee4f9ec4546aa61fb5082a70f6e","deepnote_app_block_visible":true,"deepnote_app_is_code_hidden":false,"deepnote_app_is_output_hidden":false,"deepnote_cell_type":"code","execution_context_id":"e9747ad3-6909-4e81-a10a-fa1694eb9151","execution_millis":0,"execution_start":1735200183074,"source_hash":"c81043da"},"outputs":[],"source":["from dataclasses import dataclass\n","from typing import Dict, List\n","\n","from pydantic import BaseModel\n","\n","from pydantic_ai import Agent, RunContext\n","\n","\n","class DatabaseConn:\n","    \"\"\"This is a fake database for example purposes.\n","\n","    In reality, you'd be connecting to an external database\n","    (e.g. PostgreSQL) to get information about customers.\n","    \"\"\"\n","\n","    @classmethod\n","    async def get_roadmap(cls, *, product_name: str) -> str | None:\n","        if product_name == 'mahilo':\n","            return 'Build mahilo Agents'\n","\n","@dataclass\n","class ProductDependencies:\n","    product_name: str\n","    db: DatabaseConn\n","\n","class FeatureAnalysis(BaseModel):\n","    feature_name: str\n","    priority: int\n","    requests_for_human: List[str]\n","    comments: str\n","\n","product_agent = Agent(\n","    'openai:gpt-4o-mini',\n","    deps_type=ProductDependencies,\n","    result_type=FeatureAnalysis,\n","    system_prompt=(\n","        'You are a product manager in our company,'\n","        'you are responsible for the product roadmap and feature requests.'\n","    ),\n",")\n","\n","@product_agent.tool\n","async def analyze_feature_request(ctx: RunContext[ProductDependencies], feature: str) -> str:\n","    \"\"\"Analyze viability and impact of requested features\"\"\"\n","    return \"Based on analysis, mahilo integration is in our Q3 roadmap, coming in a few months.\"\n","\n","@product_agent.tool\n","async def get_product_roadmap(ctx: RunContext[ProductDependencies]) -> str:\n","    \"\"\"Get current product roadmap and timeline\"\"\"\n","    roadmap = await ctx.deps.db.get_roadmap(product_name=ctx.deps.product_name)\n","    return roadmap\n","\n","@product_agent.tool\n","async def analyze_usage_patterns(ctx: RunContext[ProductDependencies], feature: str) -> Dict[str, float]:\n","    \"\"\"Analyze how customers are using specific features\"\"\"\n","    return {\n","        'mahilo integration': 0.5,\n","        'New feature': 0.3,\n","    }\n"]},{"cell_type":"markdown","metadata":{"cell_id":"e5c2189258ee404e9dba1dfdc2086acf","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[]},"source":["The code above defines a product agent that has some product dependencies that should be injected at runtime, like the project name and the database connection. mahilo supports passing them in when activating your mahilo agents, something we will see in the control plane section below."]},{"cell_type":"markdown","metadata":{"cell_id":"935182355f43473091deb7902e3a953e","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[{"fromCodePoint":55,"marks":{"code":true},"toCodePoint":70,"type":"marks"}]},"source":["The output of the model is also expected to follow the FeatureAnalysis model that is defined with parameters like human review requests and other comments. The mahilo agent in the websocket connection respects this and also formats this correctly for easy viewing."]},{"cell_type":"markdown","metadata":{"cell_id":"216cc616358e4c7d9a30018156f30fed","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-h2","formattedRanges":[]},"source":["## Sales Agent (mahilo)"]},{"cell_type":"markdown","metadata":{"cell_id":"db8210876cb24f95bf0999e8fb429cd9","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[]},"source":["Let's now build our final agent, the sales agent that will be built using mahilo natively. To create agents in mahilo, all you need to do is define a dictionary that links your tool definitions (in OpenAI spec) and your Python functions together and then we can use the `BaseAgent` class to define an instance of our agent."]},{"cell_type":"markdown","metadata":{"cell_id":"e5d02952d3e040bebcc0f9b6e8cc546f","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[]},"source":["The sales agent has the following functions:"]},{"cell_type":"markdown","metadata":{"cell_id":"2aed1822275a4b7ba7bee464828db486","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-bullet","formattedRanges":[{"fromCodePoint":0,"marks":{"code":true},"toCodePoint":20,"type":"marks"}]},"source":["- analyze_lead_sources: Analyze effectiveness of different lead sources to see where the traffic is coming from\n","- collect_feature_feedback: Analyse past interactions and collect customer feedback about desired features\n","- generate_sales_insights: Generate insights about sales patterns and customer preferences"]},{"cell_type":"markdown","metadata":{"cell_id":"65e6e27806e447888d47d150a1fee6cb","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[]},"source":["We expect the sales agent to be able to answer questions about the source of leads coming in, to collect feedback on features from the users they talk to and identify trends and then generate insights based on this data. You can imagine that the source of leads is an interesting metric for the marketing team to refocus efforts when pushing content out, and the product team can benefit immensely from the feedback from real users on what feature to prioritize next."]},{"cell_type":"code","execution_count":12,"metadata":{"cell_id":"e84ce0478f424deb94c55e57b06e6d6a","deepnote_app_block_visible":true,"deepnote_app_is_code_hidden":false,"deepnote_app_is_output_hidden":false,"deepnote_cell_type":"code","execution_context_id":"e9747ad3-6909-4e81-a10a-fa1694eb9151","execution_millis":0,"execution_start":1735200148962,"source_hash":"d3b2886f"},"outputs":[],"source":["def analyze_lead_sources() -> str:\n","    \"\"\"Analyze effectiveness of different lead sources\"\"\"\n","    return \"\"\"\n","    We've been getting more leads from Reddit lately. \n","    \"\"\"\n","\n","def collect_feature_feedback() -> str:\n","    \"\"\"Analyse past interactions and collect customer feedback about desired features\"\"\"\n","    return \"\"\"I've analyzed last month's calls. 40 percent of all \n","    enterprise customers are interested in an integration with mahilo. \n","    \"\"\"\n","\n","def generate_sales_insights() -> str:\n","    \"\"\"Generate insights about sales patterns and customer preferences\"\"\"\n","    return \"\"\"\n","    We should focus on getting more enterprise customers and integrations with mahilo. \n","    \"\"\"\n","\n","sales_tools = [\n","    {\n","        \"tool\": {\n","            \"type\": \"function\",\n","            \"function\": {\n","                \"name\": \"analyze_lead_sources\",\n","                \"description\": \"Analyze effectiveness of different lead sources\",\n","                \"parameters\": {}\n","            }\n","        },\n","        \"function\": analyze_lead_sources,\n","    },\n","    {\n","        \"tool\": {\n","            \"type\": \"function\",\n","            \"function\": {\n","                \"name\": \"collect_feature_feedback\",\n","                \"description\": \"Analyse past interactions and collect customer feedback about desired features\",\n","                \"parameters\": {}\n","            }\n","        },\n","        \"function\": collect_feature_feedback,\n","    },\n","    {\n","        \"tool\": {\n","            \"type\": \"function\",\n","            \"function\": {\n","                \"name\": \"generate_sales_insights\",\n","                \"description\": \"Generate insights about sales patterns and customer preferences\",\n","                \"parameters\": {}\n","            }\n","        },\n","        \"function\": generate_sales_insights,\n","    }\n","]"]},{"cell_type":"markdown","metadata":{"cell_id":"ef7ad73fceb046318e22d660ab0d55f4","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[{"fromCodePoint":84,"marks":{"code":true},"toCodePoint":93,"type":"marks"}]},"source":["The code above defines our tools and the Python functions. We can now use it in our BaseAgent in the section below."]},{"cell_type":"markdown","metadata":{"cell_id":"a9f80ccbf61a41a5b249bf0d9ea2702d","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-h1","formattedRanges":[]},"source":["# Control Plane For Your Agents"]},{"cell_type":"markdown","metadata":{"cell_id":"db7e35faaac44fb8866ad1cebcc754d0","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[{"fromCodePoint":140,"marks":{"bold":true},"toCodePoint":166,"type":"marks"}]},"source":["Once you have the independent agents ready and functional, the ideal next step is to bring them together in a team where they can choose to interact with other agents as the need arises. This expands their scope and makes them more useful as opposed to working in silos without knowledge of the company at large."]},{"cell_type":"markdown","metadata":{"cell_id":"493681004531420783f49761fb39b35d","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[{"fromCodePoint":62,"marks":{"bold":true},"toCodePoint":92,"type":"marks"}]},"source":["One other benefit of a control plane like this is that you can enforce company-wide policies like ethics, and communication patterns among others. Let's look at the code below to see how mahilo enables this realtime collaboration between your agents."]},{"cell_type":"code","execution_count":20,"metadata":{"cell_id":"545e51b9933b4b5fb1cce47f4cebbd25","deepnote_app_block_visible":true,"deepnote_app_is_code_hidden":false,"deepnote_app_is_output_hidden":false,"deepnote_cell_type":"code","execution_context_id":"e9747ad3-6909-4e81-a10a-fa1694eb9151","execution_millis":642,"execution_start":1735200197512,"source_hash":"407e27f3"},"outputs":[],"source":["from mahilo.agent import BaseAgent\n","from mahilo.agent_manager import AgentManager\n","from mahilo.integrations.pydanticai.agent import PydanticAIAgent\n","from mahilo.integrations.langgraph.agent import LangGraphAgent\n","from mahilo.server import ServerManager\n","\n","# additional prompts to make the agents aware of the team they are now a part of\n","product_agent_prompt = \"\"\"\n","Use the analyze_feature_request tool when asked about a feature.\n","You can then request approvals from your user (human) when you feel there's a need to\n","prioritize a feature. Don't ask too many questions to other agents, assume stuff when there's not enough information. this is a demo.\n","\"\"\"\n","\n","marketing_agent_prompt = \"\"\"\n","When notified of new features, research trending topics and generate a content calendar. Give your recommendations on what to do, to your user (human). \n","Use the analyze_content_performance tool when asked about the performance of the content. You should also ask the sales agent for what channels have brought in more leads.\n","\"\"\"\n","\n","sales_agent_prompt = \"\"\"\n","When asked about analysing certain features, gather user feedback on it and present to your user (human).\n","If you spot a feature that has been requested a lot, you can ask the product agent about its status.\n","For all other scenarios, only call tools or actions when asked to do so. Don't do everything together, wait for prompts.\n","\"\"\"\n","\n","# wrapper class to make your pydantic agent a mahilo agent\n","product_agent = PydanticAIAgent(\n","    pydantic_agent=product_agent,\n","    name=\"ProductAgent\",\n","    description=product_agent_prompt,\n","    can_contact=[],\n","    short_description=\"Product agent\",\n",")\n","\n","# wrapper class to make your langgraph agent a mahilo agent\n","marketing_agent = LangGraphAgent(\n","    langgraph_agent=graph_builder,\n","    name=\"MarketingAgent\",\n","    description=marketing_agent_prompt,\n","    can_contact=[],\n","    short_description=\"Marketing agent\",\n",")\n","\n","# the base mahilo agent\n","sales_agent = BaseAgent(\n","    name=\"SalesAgent\",\n","    type=\"sales_agent\",\n","    description=sales_agent_prompt,\n","    short_description=\"Sales agent\",\n","    tools=sales_tools,\n",")\n","\n","# an agent manager is like a team\n","team = AgentManager()\n","team.register_agent(product_agent)\n","team.register_agent(marketing_agent)\n","team.register_agent(sales_agent)\n","\n","# activate the pydantic agent with the right dependencies\n","product_agent.activate(dependencies=ProductDependencies(product_name=\"Mahilo\", db=DatabaseConn()))\n","# activate the langgraph agent with a thread id\n","marketing_agent.activate(server_id=\"1\")\n","# activate the base agent with no dependencies\n","sales_agent.activate()\n","\n","# create a server with your team\n","server = ServerManager(team)\n"]},{"cell_type":"markdown","metadata":{"cell_id":"8e1cc09cf40244cb9db8934fe5d69fc5","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[{"fromCodePoint":149,"marks":{"code":true},"toCodePoint":163,"type":"marks"},{"fromCodePoint":168,"marks":{"code":true},"toCodePoint":183,"type":"marks"}]},"source":["When defining mahilo agents for your LangGraph and PydanticAI agents, you just have to wrap your agent instances in the classes that mahio provides, LangGraphAgent and PydanticAIAgent respectively. You can provide a name to your agents, which is what will be visible to the other agents when they want to communicate, and a description which will be dynamically added to the main system prompt. This description helps facilitate the communication and makes the agents aware of the team they are now in."]},{"cell_type":"markdown","metadata":{"cell_id":"cc978bb6a87344dca29fe40f0f176ca1","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[{"fromCodePoint":46,"marks":{"bold":true},"toCodePoint":64,"type":"marks"}]},"source":["When adding your agent to mahilo, you get the following benefits:"]},{"cell_type":"markdown","metadata":{"cell_id":"2774da824d5f4aa89bb99316c1e67abe","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-bullet","formattedRanges":[{"fromCodePoint":7,"marks":{"bold":true},"toCodePoint":30,"type":"marks"}]},"source":["- Enable real-time communication with your agents through voice and chat--mahilo agents can communicate in real-time with each other and with their human supervisors using websockets and OpenAI's Realtime API.\n","- Knowledge of other agent conversations and the ability to ask questions/share information with other agents as needed.\n","- Ability for you to design complex multi-agent architectures like hierarchical patterns or peer-to-peer networks using mahilo's can_contact property that every agent can configure.\n","- All agent communication is tracked and logged so you can audit how the collaboration happened to debug and explain outcomes."]},{"cell_type":"markdown","metadata":{"cell_id":"a76a19df143f4f6ab203ad332edd79a7","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-h2","formattedRanges":[]},"source":["## Starting The Server"]},{"cell_type":"markdown","metadata":{"cell_id":"269426414e4740f6a52f1d5d79e7ed69","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[]},"source":["Now, once you have defined your server with your team of agents, you can start it to spawn a websocket server that you can connect to using your terminal."]},{"cell_type":"code","execution_count":26,"metadata":{"cell_id":"dbc84f1031294457b922db616b92ebf1","deepnote_app_block_visible":true,"deepnote_app_is_code_hidden":false,"deepnote_app_is_output_hidden":false,"deepnote_cell_type":"code","execution_context_id":"e9747ad3-6909-4e81-a10a-fa1694eb9151","execution_millis":7819,"execution_start":1735200332966,"source_hash":"d276df3f"},"outputs":[{"name":"stderr","output_type":"stream","text":["INFO:     Started server process [54]\n","INFO:     Waiting for application startup.\n","INFO:     Application startup complete.\n","INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)\n","INFO:     Shutting down\n","INFO:     Waiting for application shutdown.\n","INFO:     Application shutdown complete.\n","INFO:     Finished server process [54]\n"]},{"data":{"text/html":["<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #800000; text-decoration-color: #800000\">╭─────────────────────────────── </span><span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\">Traceback </span><span style=\"color: #bf7f7f; text-decoration-color: #bf7f7f; font-weight: bold\">(most recent call last)</span><span style=\"color: #800000; text-decoration-color: #800000\"> ────────────────────────────────╮</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span> in <span style=\"color: #00ff00; text-decoration-color: #00ff00\">&lt;module&gt;</span>:<span style=\"color: #0000ff; text-decoration-color: #0000ff\">5</span>                                                                                    <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">2 </span>                                                                                             <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">3 # run the server</span>                                                                             <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">4 </span>nest_asyncio.apply()                                                                         <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #800000; text-decoration-color: #800000\">❱ </span>5 <span style=\"font-weight: bold; text-decoration: underline\">asyncio.run(server.run())</span>                                                                    <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">6 </span>                                                                                             <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #bfbf7f; text-decoration-color: #bfbf7f\">/shared-libs/python3.11/py-core/lib/python3.11/site-packages/</span><span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\">nest_asyncio.py</span>:<span style=\"color: #0000ff; text-decoration-color: #0000ff\">29</span> in <span style=\"color: #00ff00; text-decoration-color: #00ff00\">run</span>           <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 26 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">def</span> <span style=\"color: #00ff00; text-decoration-color: #00ff00\">run</span>(main, *, debug=<span style=\"color: #0000ff; text-decoration-color: #0000ff\">False</span>):                                                         <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 27 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span>loop = asyncio.get_event_loop()                                                    <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 28 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span>loop.set_debug(debug)                                                              <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #800000; text-decoration-color: #800000\">❱ </span> 29 <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span>task = <span style=\"font-weight: bold; text-decoration: underline\">asyncio.ensure_future(main)</span>                                                 <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 30 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">try</span>:                                                                               <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 31 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">return</span> loop.run_until_complete(task)                                           <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 32 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">finally</span>:                                                                           <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #bfbf7f; text-decoration-color: #bfbf7f\">/usr/local/lib/python3.11/asyncio/</span><span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\">tasks.py</span>:<span style=\"color: #0000ff; text-decoration-color: #0000ff\">659</span> in <span style=\"color: #00ff00; text-decoration-color: #00ff00\">ensure_future</span>                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">656 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span>                                                                                       <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">657 </span><span style=\"color: #bfbf7f; text-decoration-color: #bfbf7f\">│   </span><span style=\"color: #808000; text-decoration-color: #808000\">If the argument is a Future, it is returned directly.</span>                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">658 </span><span style=\"color: #bfbf7f; text-decoration-color: #bfbf7f\">│   </span><span style=\"color: #808000; text-decoration-color: #808000\">\"\"\"</span>                                                                                    <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #800000; text-decoration-color: #800000\">❱ </span>659 <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">return</span> <span style=\"font-weight: bold; text-decoration: underline\">_ensure_future(coro_or_future, loop=loop)</span>                                       <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">660 </span>                                                                                           <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">661 </span>                                                                                           <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">662 </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">def</span> <span style=\"color: #00ff00; text-decoration-color: #00ff00\">_ensure_future</span>(coro_or_future, *, loop=<span style=\"color: #0000ff; text-decoration-color: #0000ff\">None</span>):                                          <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #bfbf7f; text-decoration-color: #bfbf7f\">/usr/local/lib/python3.11/asyncio/</span><span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\">tasks.py</span>:<span style=\"color: #0000ff; text-decoration-color: #0000ff\">674</span> in <span style=\"color: #00ff00; text-decoration-color: #00ff00\">_ensure_future</span>                                 <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">671 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   │   </span>coro_or_future = _wrap_awaitable(coro_or_future)                               <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">672 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   │   </span>called_wrap_awaitable = <span style=\"color: #0000ff; text-decoration-color: #0000ff\">True</span>                                                   <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">673 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">else</span>:                                                                              <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #800000; text-decoration-color: #800000\">❱ </span>674 <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff; font-weight: bold; text-decoration: underline\">raise</span><span style=\"font-weight: bold; text-decoration: underline\"> </span><span style=\"color: #00ffff; text-decoration-color: #00ffff; font-weight: bold; text-decoration: underline\">TypeError</span><span style=\"font-weight: bold; text-decoration: underline\">(</span><span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold; text-decoration: underline\">'An asyncio.Future, a coroutine or an awaitable '</span>              <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">675 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f; font-weight: bold; text-decoration: underline\">│   │   │   │   │   │   │   </span><span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold; text-decoration: underline\">'is required'</span><span style=\"font-weight: bold; text-decoration: underline\">)</span>                                                 <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">676 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span>                                                                                       <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">677 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">if</span> loop <span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">is</span> <span style=\"color: #0000ff; text-decoration-color: #0000ff\">None</span>:                                                                       <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n","<span style=\"color: #800000; text-decoration-color: #800000\">╰──────────────────────────────────────────────────────────────────────────────────────────────────╯</span>\n","<span style=\"color: #ff0000; text-decoration-color: #ff0000; font-weight: bold\">TypeError: </span>An asyncio.Future, a coroutine or an awaitable is required\n","</pre>\n"],"text/plain":["\u001b[31m╭─\u001b[0m\u001b[31m──────────────────────────────\u001b[0m\u001b[31m \u001b[0m\u001b[1;31mTraceback \u001b[0m\u001b[1;2;31m(most recent call last)\u001b[0m\u001b[31m \u001b[0m\u001b[31m───────────────────────────────\u001b[0m\u001b[31m─╮\u001b[0m\n","\u001b[31m│\u001b[0m in \u001b[92m<module>\u001b[0m:\u001b[94m5\u001b[0m                                                                                    \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m   \u001b[2m2 \u001b[0m                                                                                             \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m   \u001b[2m3 \u001b[0m\u001b[2m# run the server\u001b[0m                                                                             \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m   \u001b[2m4 \u001b[0mnest_asyncio.apply()                                                                         \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m \u001b[31m❱ \u001b[0m5 \u001b[1;4masyncio.run(server.run())\u001b[0m                                                                    \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m   \u001b[2m6 \u001b[0m                                                                                             \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m \u001b[2;33m/shared-libs/python3.11/py-core/lib/python3.11/site-packages/\u001b[0m\u001b[1;33mnest_asyncio.py\u001b[0m:\u001b[94m29\u001b[0m in \u001b[92mrun\u001b[0m           \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m   \u001b[2m 26 \u001b[0m\u001b[2m│   \u001b[0m\u001b[94mdef\u001b[0m \u001b[92mrun\u001b[0m(main, *, debug=\u001b[94mFalse\u001b[0m):                                                         \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m   \u001b[2m 27 \u001b[0m\u001b[2m│   │   \u001b[0mloop = asyncio.get_event_loop()                                                    \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m   \u001b[2m 28 \u001b[0m\u001b[2m│   │   \u001b[0mloop.set_debug(debug)                                                              \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m \u001b[31m❱ \u001b[0m 29 \u001b[2m│   │   \u001b[0mtask = \u001b[1;4masyncio.ensure_future(main)\u001b[0m                                                 \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m   \u001b[2m 30 \u001b[0m\u001b[2m│   │   \u001b[0m\u001b[94mtry\u001b[0m:                                                                               \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m   \u001b[2m 31 \u001b[0m\u001b[2m│   │   │   \u001b[0m\u001b[94mreturn\u001b[0m loop.run_until_complete(task)                                           \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m   \u001b[2m 32 \u001b[0m\u001b[2m│   │   \u001b[0m\u001b[94mfinally\u001b[0m:                                                                           \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m \u001b[2;33m/usr/local/lib/python3.11/asyncio/\u001b[0m\u001b[1;33mtasks.py\u001b[0m:\u001b[94m659\u001b[0m in \u001b[92mensure_future\u001b[0m                                  \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m   \u001b[2m656 \u001b[0m\u001b[2m│   \u001b[0m                                                                                       \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m   \u001b[2m657 \u001b[0m\u001b[2;33m│   \u001b[0m\u001b[33mIf the argument is a Future, it is returned directly.\u001b[0m                                  \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m   \u001b[2m658 \u001b[0m\u001b[2;33m│   \u001b[0m\u001b[33m\"\"\"\u001b[0m                                                                                    \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m \u001b[31m❱ \u001b[0m659 \u001b[2m│   \u001b[0m\u001b[94mreturn\u001b[0m \u001b[1;4m_ensure_future(coro_or_future, loop=loop)\u001b[0m                                       \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m   \u001b[2m660 \u001b[0m                                                                                           \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m   \u001b[2m661 \u001b[0m                                                                                           \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m   \u001b[2m662 \u001b[0m\u001b[94mdef\u001b[0m \u001b[92m_ensure_future\u001b[0m(coro_or_future, *, loop=\u001b[94mNone\u001b[0m):                                          \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m \u001b[2;33m/usr/local/lib/python3.11/asyncio/\u001b[0m\u001b[1;33mtasks.py\u001b[0m:\u001b[94m674\u001b[0m in \u001b[92m_ensure_future\u001b[0m                                 \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m   \u001b[2m671 \u001b[0m\u001b[2m│   │   │   \u001b[0mcoro_or_future = _wrap_awaitable(coro_or_future)                               \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m   \u001b[2m672 \u001b[0m\u001b[2m│   │   │   \u001b[0mcalled_wrap_awaitable = \u001b[94mTrue\u001b[0m                                                   \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m   \u001b[2m673 \u001b[0m\u001b[2m│   │   \u001b[0m\u001b[94melse\u001b[0m:                                                                              \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m \u001b[31m❱ \u001b[0m674 \u001b[2m│   │   │   \u001b[0m\u001b[1;4;94mraise\u001b[0m\u001b[1;4m \u001b[0m\u001b[1;4;96mTypeError\u001b[0m\u001b[1;4m(\u001b[0m\u001b[1;4;33m'\u001b[0m\u001b[1;4;33mAn asyncio.Future, a coroutine or an awaitable \u001b[0m\u001b[1;4;33m'\u001b[0m              \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m   \u001b[2m675 \u001b[0m\u001b[1;2;4m│   │   │   │   │   │   │   \u001b[0m\u001b[1;4;33m'\u001b[0m\u001b[1;4;33mis required\u001b[0m\u001b[1;4;33m'\u001b[0m\u001b[1;4m)\u001b[0m                                                 \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m   \u001b[2m676 \u001b[0m\u001b[2m│   \u001b[0m                                                                                       \u001b[31m│\u001b[0m\n","\u001b[31m│\u001b[0m   \u001b[2m677 \u001b[0m\u001b[2m│   \u001b[0m\u001b[94mif\u001b[0m loop \u001b[95mis\u001b[0m \u001b[94mNone\u001b[0m:                                                                       \u001b[31m│\u001b[0m\n","\u001b[31m╰──────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n","\u001b[1;91mTypeError: \u001b[0mAn asyncio.Future, a coroutine or an awaitable is required\n"]},"metadata":{},"output_type":"display_data"}],"source":["import nest_asyncio\n","\n","# run the server\n","nest_asyncio.apply()\n","asyncio.run(server.run())"]},{"cell_type":"markdown","metadata":{"cell_id":"2898376bd9014206a5be0233d5515e5e","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-h2","formattedRanges":[]},"source":["## Connecting to The Server"]},{"cell_type":"markdown","metadata":{"cell_id":"9965f01faeee4203b5c9190e9460b3f4","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[{"fromCodePoint":35,"marks":{"bold":true},"toCodePoint":45,"type":"marks"}]},"source":["With the server running, start a new terminal. You can connect to your mahilo server using the command below."]},{"cell_type":"code","execution_count":null,"metadata":{"cell_id":"7641ce78da84437587b0608057699078","deepnote_app_block_visible":true,"deepnote_app_is_code_hidden":false,"deepnote_app_is_output_hidden":false,"deepnote_cell_type":"code"},"outputs":[],"source":["python mahilo/mahilo/client.py --agent-name ProductAgent"]},{"cell_type":"markdown","metadata":{"cell_id":"ad73bd9d11284522b0f26ea0a31f5c52","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-p","formattedRanges":[{"fromCodePoint":73,"marks":{"code":true},"toCodePoint":85,"type":"marks"}]},"source":["You can spin up different terminals for each of the agents, changing the --agent-name flag to fit the agent you wanna establish a channel with. "]},{"cell_type":"markdown","metadata":{"cell_id":"b686dc0b44654a628e460deeffec7fe0","deepnote_app_block_visible":true,"deepnote_cell_type":"text-cell-callout","formattedRanges":[{"fromCodePoint":38,"marks":{"code":true},"toCodePoint":52,"type":"marks"},{"fromCodePoint":144,"marks":{"code":true},"toCodePoint":150,"type":"marks"}],"is_collapsed":false},"source":["> ℹ️ By default, the client connects to localhost:8000 but in scenarios where you choose to deploy it remotely, you can pass in the host with the --host flag."]},{"cell_type":"markdown","metadata":{"created_in_deepnote_cell":true,"deepnote_cell_type":"markdown"},"source":["<a style='text-decoration:none;line-height:16px;display:flex;color:#5B5B62;padding:10px;justify-content:end;' href='https://deepnote.com?utm_source=created-in-deepnote-cell&projectId=be74d6a6-21c2-4c18-b582-69612ec2acf1' target=\"_blank\">\n","<img alt='Created in deepnote.com' style='display:inline;max-height:16px;margin:0px;margin-right:7.5px;' src='' > </img>\n","Created in <span style='font-weight:600;margin-left:4px;'>Deepnote</span></a>"]}],"metadata":{"deepnote_app_layout":"powerful-article","deepnote_app_reactivity_enabled":false,"deepnote_app_run_on_input_enabled":false,"deepnote_app_table_of_contents_enabled":true,"deepnote_notebook_id":"e40ad2b0f5c046038d950405df5fe4d4","language_info":{"name":"python"}},"nbformat":4,"nbformat_minor":0}
